/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ceair.flight.refund.service.notification.impl;

import com.ceair.flight.refund.dto.external.RefundApply;
import com.ceair.flight.refund.dto.external.RefundSeg;
import com.ceair.flight.refund.dto.external.RefundTkt;
import com.ceair.flight.refund.location.dt.enums.RefundStatusEnum;
import com.ceair.flight.refund.location.service.IRefundLocationService;
import com.ceair.flight.refund.service.notification.IRefundNotifcation;
import com.ceair.flight.refund.util.GsonUtil;
import com.ceair.muservice.basicdata.dto.airport.AirportDto;
import com.ceair.muservice.basicdata.dto.channel.ChannelManageDto;
import com.ceair.muservice.common.dto.queue.MailAndSMSMessage;
import com.ceair.muservice.common.enums.message.TemplateNameEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Colin_You
 */
@Service
public class RefundRejectNotifcation extends AbstractNotification implements IRefundNotifcation {

    private static final Logger LOG = LoggerFactory.getLogger(UatpRefundNotification.class);
    private static final String TICKET_NO = "TICKET_NO"; //票号
    private static final String ORDER_NO = "ORDER_NO"; //订单号
    private static final String SEGMENTS = "SEGMENTS";//航段列表
    private static final String FLIGHT_NO = "FLIGHT_NO";//航班号
    private static final String DEP_CODE = "DEP_CODE";//出发机场
    private static final String ARR_CODE = "ARR_CODE";//到达机场
    private static final String DEP_DATE = "DEP_DATE";//出发日期

     @Autowired
    private IRefundLocationService refundLocationService;

    @Override
    TemplateNameEnum getTemplateName(Map args) {
        if (args.containsKey(MOBILES)) {
            return TemplateNameEnum.REFUND_REFUSE_SMS;
        }
        return TemplateNameEnum.REFUND_REFUSE_MAIL;
    }

    @Override
    public boolean sendNotification(RefundApply refundApply) {
        if (!isValidForSend(refundApply)) {
            LOG.warn("Refund apply {} not valid for sending refund rejection notifications", refundApply.getId());
            return false;
        }
        boolean isMailSuccess = false;
        boolean isSmsSuccess = false;
        Map args = buildCommonArgs(refundApply);
        try {
            sendMail(new HashMap(args), refundApply);
            isMailSuccess = true;
            LOG.debug("Send refund rejection email message successfully");
        } catch (Exception ex) {
            LOG.error("Send refund rejection mail message failed", ex);
        }
        try {
            sendSms(new HashMap(args), refundApply);
            isSmsSuccess = true;
            LOG.debug("Send refund rejection sms message successfully");
        } catch (Exception ex) {
            LOG.error("Send refund rejection sms message failed", ex);
        }
        return isMailSuccess || isSmsSuccess;
    }

    @Override
    public void notify(final Map args) {
        MailAndSMSMessage message = buildMessage(args);
        if (message != null) {
            String messageEntity = GsonUtil.toJson(message);
            LOG.debug("Refund reject notification message entity: {}", messageEntity);
            getMessageSender().sendMessage(message);
        } else {
            throw new IllegalStateException("Send failed");
        }
    }

    private boolean isValidForSend(RefundApply refundApply) {
        String status = refundApply.getStatus();
        RefundStatusEnum statusEnum = RefundStatusEnum.getByCode(status);
        return RefundStatusEnum.WAIT_USER_UPDATE == statusEnum;
    }

    private Map buildCommonArgs(RefundApply refundApply) {
        RefundTkt refundTkt = refundApply.getRefundTkt();
        Map args = new HashMap(2, 1.0f);
        String channelNo = refundTkt.getChannelNo();
        args.put(TICKET_NO, refundTkt.getTicketNo());
        args.put(ORDER_NO, refundTkt.getOrderNo());
        List<RefundSeg> segs = refundTkt.getSortSegs();
        Set<String> codeSet = new HashSet<>();
        for (RefundSeg seg:segs){
            String depCd = seg.getDepartAirport();
            String arrCd = seg.getArriveAirport();
            codeSet.add(depCd);
            codeSet.add(arrCd);
        }
        List<String> codeList = new ArrayList<>(codeSet);
        ChannelManageDto channelManageDto = refundLocationService.findChannelByCode(channelNo);
        Map<String, AirportDto> nationCityAirportDtoMap = refundLocationService.findNationCityAirNameByCodes(codeList);
        List segList = getSegments(segs,nationCityAirportDtoMap, channelManageDto.getLanguageCode());
        args.put(SEGMENTS, segList);
        return args;
    }

    private List getSegments(List<RefundSeg> segs, Map<String, AirportDto> nationCityAirportDtoMap, String languageCode) {
        List list = new ArrayList<>(segs.size());
        for (RefundSeg seg : segs) {
            list.add(fillSeg(seg, nationCityAirportDtoMap, languageCode));
        }
        return list;
    }

    private Map fillSeg(RefundSeg seg, Map<String, AirportDto> nationCityAirportDtoMap, String languageCode) {
        Map result = new HashMap<>(4, 1.0f);
        result.put(FLIGHT_NO, seg.getFlightNo());
        String depCode = seg.getDepartAirport();
        result.put(DEP_CODE, nationCityAirportDtoMap.get(depCode).getName(languageCode));
        String arrCode = seg.getArriveAirport();
        result.put(ARR_CODE, nationCityAirportDtoMap.get(arrCode).getName(languageCode));
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
        Date depDate = seg.getDepartDate();
        String depDateStr = df.format(depDate);
        result.put(DEP_DATE, depDateStr);
        return result;
    }
    private void sendMail(Map args, RefundApply refundApply) {
        String mailAddress = getMailAddress(refundApply);
        if (mailAddress == null || mailAddress.isEmpty()) {
            LOG.error("No available email address for refund rejection notification");
            throw new IllegalStateException("No available email address for  refund rejection notification, stopping sending email notificaton");
        }
        args.put(RECEIVER, mailAddress);
        this.notify(args);
    }

    private void sendSms(Map args, RefundApply refundApply) {
        String phone = getPhoneNumber(refundApply);
        if (phone == null || phone.isEmpty()) {
            LOG.error("No available phone for refund rejection notification");
            throw new IllegalStateException("No available phone for  refund rejection notification, stopping sending sms notificaton");
        }
        args.put(MOBILES, phone);
        args.put(IS_INTER, isDomesticPhoneNo(phone) ? "0" : "1");
        this.notify(args);
    }

    boolean isDomesticPhoneNo(String phone) {
        return phone.startsWith("86") || phone.startsWith("+86") || phone.length() == 11;
    }

    /**
     * 获取通知邮件信息,订单中填的联系邮箱优先,然后才是乘客信息中的邮箱信息
     *
     * @param refundApply
     * @return
     */
    private String getMailAddress(RefundApply refundApply) {
        String email = refundApply.getContactEmail();
        if (email != null && !email.isEmpty()) {
            return email;
        }
        RefundTkt refundTkt = refundApply.getRefundTkt();
        return refundTkt.getPaxEmail();
    }

    /**
     * 获取通知电话信息,订单中填的联系电话优先,然后才是乘客信息中的电话信息
     *
     * @param refundApply
     * @return
     */
    private String getPhoneNumber(RefundApply refundApply) {
        String phone = refundApply.getContactPhone();
        if (phone != null && !phone.isEmpty()) {
            return phone;
        }
        RefundTkt refundTkt = refundApply.getRefundTkt();
        return refundTkt.getPaxPhone();
    }

}
